/// 枚举还可以解决变量多类型问题
/// 传统语言的枚举是做不到的
/// 

#[derive(Debug)]
struct SingleClient {}
impl SingleClient {
  fn new() -> SingleClient {
    return SingleClient {};
  }
  fn print(&self) {
    println!("`{:?} print()`", self);
  }
}

#[derive(Debug)]
struct ClusterClient {}

impl ClusterClient {
  fn new() -> ClusterClient {
    ClusterClient {}
  }
  fn print(&self) {
    println!("`{:?} print()`", self);
  }
}

enum ClientType {
  SingleClientType(SingleClient),
  ClusterClientType(ClusterClient),
}

struct Demo {
  client: ClientType,
}

/// 枚举取值封装器
/// 由于枚举不是trait类型所以这样定义非法
// fn get_enum_type<T: ClientType>(value :T)->T {

// }

// fn get_client_type_value<T>(value: &ClientType)->Box<dyn T> {
//   match value {
//     ClientType::SingleClientType(client) => {
//       return Box::<SingleClient>::new(client);
//     }
//     ClientType::ClusterClientType(client) => {
//       return Box::<ClusterClient>::new(client);
//     }
//   }
// }


impl Demo {
  fn new() -> Demo {
    Demo {
      client: ClientType::SingleClientType(SingleClient {}),
    }
  }
  fn init(&mut self, is_single: bool) -> Result<(), ()> {
    if is_single {
      self.client = ClientType::SingleClientType(SingleClient::new());
    } else {
      self.client = ClientType::ClusterClientType(ClusterClient::new());
    }
    Ok(())
  }
}

#[cfg(test)]
mod tests {
  #[test]
  fn test_enum() {
    use super::*;
    let mut demo = Demo::new();
    demo.init(true).expect("Failed to initialize");
    // 通过match的方式对枚举类型取值
    match demo.client {
      ClientType::SingleClientType(client) => {
        client.print();
      }
      ClientType::ClusterClientType(client) => {
        client.print();
      }
    }
  }

  #[test]
  fn test_enum2() {
    use super::*;
    let mut demo = Demo::new();
    demo.init(false).expect("Failed to initialize");
    // 通过if let的方式对枚举类型取值
    if let ClientType::SingleClientType(client) = demo.client {
      client.print();
    } 
  }
}
